/* 实现一个RawBuffer，从Vec中接收数据
方案选型中，可以直接用指针存储Buffer中的数据，然后自己维护数据。（灵活+性能高）
也可以直接使用Box的结构组织buffer中的数据。（简单+安全）

本次采用裸指针的方式组织buffer中的数据。
依据上述要求，需要实现类型转换的From接口，自己维护内存意味着需要实现Drap接口
*/

use std::{fmt, slice};

struct RawBuffer {
    ptr: *mut u8, // 使用裸指针自行维护
    len: usize,
}

//  另外一种实现
// struct RawBuffer2 {
//     data: Box<[u8]>,
// }

// impl From<Vec<u8>> for RawBuffer2 {
//     fn from(value: Vec<u8>) -> Self {
//         Self {
//             data: value.into_boxed_slice(),
//         }
//     }
// }

// 从Vec中接收数据，需要实现from trait
impl From<Vec<u8>> for RawBuffer {
    fn from(value: Vec<u8>) -> Self {
        // 将vec引用对象转化为box智能指针，然后获取到其中的真实数据
        let data: Box<[u8]> = value.into_boxed_slice();
        Self {
            len: data.len(),
            ptr: Box::into_raw(data) as *mut u8,
            // 获取到box的真实指针数据，然后这份数据就和box无关了，需要手动维护
        }
    }
}

// 既然使用了裸指针，就需要手动实现drop来维护内存的回收
// 只要把具体的数据赋值给
impl Drop for RawBuffer {
    fn drop(&mut self) {
        // try1: let _ = unsafe { *self.ptr }; // 但是这样解引用只会得到数据的内存快的引用，并不会释放内存。（在Rust中，解引用一个裸指针只会给你一个指向内存的引用，但并不会释放这块内存）
        // try2: let _ = unsafe { Box::from_raw( self.ptr ) }; // 看起来没有问题，但是，在这个上下文里，只会释放掉vec数组的第一个元素
        // 想释放这块内存，你需要将这个裸指针转换回一个Box，然后让这个Box离开作用域，这样Rust就会自动释放这块内存
        print!("drop rawbuffer");
        let _ = unsafe { Box::from_raw(slice::from_raw_parts_mut(self.ptr, self.len)) };
        /*
        slice::from_raw_parts和slice::from_raw_parts_mut函数都可以用来
        从裸指针和长度创建一个切片。这两个函数的区别在于，
        slice::from_raw_parts创建的是一个不可变切片（&[T]），
        而slice::from_raw_parts_mut创建的是一个可变切片（&mut [T]）。
         */
    }
}

fn use_buf(buf: RawBuffer) {
    println!("use_buf: data={:?} , len={:?}", buf.ptr, buf.len)
}

fn main() {
    let data = RawBuffer::from(vec![1, 2, 3, 4]);
    println!("原始数据： {:#?}, len={:?}", data, data.len);

    use_buf(data); // 所有权发生了转移
}

// 便于调试的目的，我们实现Debug trait
// 在println！的时候会将相应的内容输出
// 类型必须实现了Debug trait，你才能在格式化字符串中使用{:?}或者{:#?}占位符。
impl fmt::Debug for RawBuffer {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // 简单打印
        // f.debug_struct("RawBuffer")
        //     .field("len", &self.len)
        //     .field("ptr", &self.ptr)
        //     .finish()

        let data = self.as_ref();
        write!(f, "[debug]{:?}\n", data)
    }
}

// 用于从某一个引用具体的对象,调用AsRef会返回一个指向RawBuffer内部数据的切片
// impl AsRef for RawBuffer {
impl AsRef<[u8]> for RawBuffer {
    fn as_ref(&self) -> &[u8] {
        unsafe { slice::from_raw_parts_mut(self.ptr, self.len) }
    }
}

/*
注意，Box::from_raw和slice::from_raw_parts_mut函数都是unsafe的，
因为它们需要一个有效的裸指针。
*/
